import json
import redis
from typing import Any, List, Dict, Set, Optional, Union, Tuple
from django.conf import settings
import uuid
import time


class RedisClient:
    """
    通用Redis工具类，基于原生redis包实现，不依赖django-redis
    提供各种Redis数据类型的通用操作方法，不包含任何业务逻辑
    """

    def __init__(self, host: str = None, port: int = None, db: int = None, password: str = None):
        """
        初始化Redis连接
        优先使用settings中的配置，其次使用参数，最后使用默认值
        """
        self.host = host or getattr(settings, 'REDIS_HOST', 'localhost')
        self.port = port or getattr(settings, 'REDIS_PORT', 6379)
        self.db = db or getattr(settings, 'REDIS_DB', 0)
        self.password = password or getattr(settings, 'REDIS_PASSWORD', None)

        # 创建Redis连接池
        self.pool = redis.ConnectionPool(
            host=self.host,
            port=self.port,
            db=self.db,
            password=self.password,
            decode_responses=False  # 不自动解码，保持bytes类型便于统一处理
        )

        # 获取连接
        self.client = redis.Redis(connection_pool=self.pool)

    def _serialize(self, value: Any) -> bytes:
        """将Python对象序列化为JSON bytes"""
        if value is None:
            return b''
        return json.dumps(value, ensure_ascii=False).encode('utf-8')

    def _deserialize(self, value: bytes) -> Any:
        """将JSON bytes反序列化为Python对象"""
        if not value:
            return None
        try:
            return json.loads(value.decode('utf-8'))
        except (json.JSONDecodeError, UnicodeDecodeError):
            return value.decode('utf-8', errors='ignore')

    # ==========================================
    # 字符串(String)操作
    # ==========================================

    def set(self, key: str, value: Any, ex: Optional[int] = None, nx: bool = False) -> bool:
        """
        设置字符串值
        :param key: 键
        :param value: 值
        :param ex: 过期时间(秒)
        :param nx: 如果为True，仅当key不存在时才设置
        :return: 是否成功
        """
        try:
            return self.client.set(
                name=key,
                value=self._serialize(value),
                ex=ex,
                nx=nx
            ) is not None
        except Exception as e:
            print(f"Redis set error: {str(e)}")
            return False

    def get(self, key: str) -> Any:
        """
        获取字符串值
        :param key: 键
        :return: 反序列化后的值
        """
        try:
            value = self.client.get(key)
            return self._deserialize(value)
        except Exception as e:
            print(f"Redis get error: {str(e)}")
            return None

    def delete(self, *keys: str) -> int:
        """
        删除一个或多个键
        :param keys: 键列表
        :return: 被删除的键的数量
        """
        try:
            return self.client.delete(*keys)
        except Exception as e:
            print(f"Redis delete error: {str(e)}")
            return 0

    def expire(self, key: str, seconds: int) -> bool:
        """
        设置键的过期时间
        :param key: 键
        :param seconds: 过期时间(秒)
        :return: 是否成功
        """
        try:
            return self.client.expire(key, seconds)
        except Exception as e:
            print(f"Redis expire error: {str(e)}")
            return False

    def exists(self, key: str) -> bool:
        """
        判断键是否存在
        :param key: 键
        :return: 是否存在
        """
        try:
            return self.client.exists(key) > 0
        except Exception as e:
            print(f"Redis exists error: {str(e)}")
            return False

    # ==========================================
    # 哈希(Hash)操作
    # ==========================================

    def hset(self, name: str, key: str, value: Any) -> bool:
        """
        设置哈希字段值
        :param name: 哈希表名称
        :param key: 字段名
        :param value: 字段值
        :return: 是否成功
        """
        try:
            return self.client.hset(
                name=name,
                key=key,
                value=self._serialize(value)
            ) > 0
        except Exception as e:
            print(f"Redis hset error: {str(e)}")
            return False

    def hmset(self, name: str, mapping: Dict[str, Any]) -> bool:
        """
        批量设置哈希字段值
        :param name: 哈希表名称
        :param mapping: 字段-值字典
        :return: 是否成功
        """
        try:
            serialized_mapping = {
                k: self._serialize(v)
                for k, v in mapping.items()
            }
            return self.client.hset(name, mapping=serialized_mapping) > 0
        except Exception as e:
            print(f"Redis hmset error: {str(e)}")
            return False

    def hget(self, name: str, key: str) -> Any:
        """
        获取哈希字段值
        :param name: 哈希表名称
        :param key: 字段名
        :return: 反序列化后的值
        """
        try:
            value = self.client.hget(name, key)
            return self._deserialize(value)
        except Exception as e:
            print(f"Redis hget error: {str(e)}")
            return None

    def hmget(self, name: str, keys: List[str]) -> List[Any]:
        """
        批量获取哈希字段值
        :param name: 哈希表名称
        :param keys: 字段名列表
        :return: 反序列化后的值列表
        """
        try:
            values = self.client.hmget(name, keys)
            return [self._deserialize(v) for v in values]
        except Exception as e:
            print(f"Redis hmget error: {str(e)}")
            return []

    def hgetall(self, name: str) -> Dict[str, Any]:
        """
        获取哈希表所有字段和值
        :param name: 哈希表名称
        :return: 包含所有字段和值的字典
        """
        try:
            items = self.client.hgetall(name)
            return {
                k.decode('utf-8'): self._deserialize(v)
                for k, v in items.items()
            }
        except Exception as e:
            print(f"Redis hgetall error: {str(e)}")
            return {}

    def hdel(self, name: str, *keys: str) -> int:
        """
        删除哈希表字段
        :param name: 哈希表名称
        :param keys: 字段名列表
        :return: 被删除的字段数量
        """
        try:
            return self.client.hdel(name, *keys)
        except Exception as e:
            print(f"Redis hdel error: {str(e)}")
            return 0

    def hkeys(self, name: str) -> List[str]:
        """
        获取哈希表所有字段名
        :param name: 哈希表名称
        :return: 字段名列表
        """
        try:
            keys = self.client.hkeys(name)
            return [k.decode('utf-8') for k in keys]
        except Exception as e:
            print(f"Redis hkeys error: {str(e)}")
            return []

    # ==========================================
    # 列表(List)操作
    # ==========================================

    def lpush(self, name: str, *values: Any) -> int:
        """
        向左插入列表元素
        :param name: 列表名称
        :param values: 要插入的值
        :return: 插入后列表长度
        """
        try:
            serialized_values = [self._serialize(v) for v in values]
            return self.client.lpush(name, *serialized_values)
        except Exception as e:
            print(f"Redis lpush error: {str(e)}")
            return 0

    def rpush(self, name: str, *values: Any) -> int:
        """
        向右插入列表元素
        :param name: 列表名称
        :param values: 要插入的值
        :return: 插入后列表长度
        """
        try:
            serialized_values = [self._serialize(v) for v in values]
            return self.client.rpush(name, *serialized_values)
        except Exception as e:
            print(f"Redis rpush error: {str(e)}")
            return 0

    def lrange(self, name: str, start: int, end: int) -> List[Any]:
        """
        获取列表指定范围的元素
        :param name: 列表名称
        :param start: 起始索引
        :param end: 结束索引，-1表示最后一个元素
        :return: 元素列表
        """
        try:
            values = self.client.lrange(name, start, end)
            return [self._deserialize(v) for v in values]
        except Exception as e:
            print(f"Redis lrange error: {str(e)}")
            return []

    def lpop(self, name: str) -> Any:
        """
        从左侧弹出元素
        :param name: 列表名称
        :return: 弹出的元素
        """
        try:
            value = self.client.lpop(name)
            return self._deserialize(value)
        except Exception as e:
            print(f"Redis lpop error: {str(e)}")
            return None

    def rpop(self, name: str) -> Any:
        """
        从右侧弹出元素
        :param name: 列表名称
        :return: 弹出的元素
        """
        try:
            value = self.client.rpop(name)
            return self._deserialize(value)
        except Exception as e:
            print(f"Redis rpop error: {str(e)}")
            return None

    def llen(self, name: str) -> int:
        """
        获取列表长度
        :param name: 列表名称
        :return: 列表长度
        """
        try:
            return self.client.llen(name)
        except Exception as e:
            print(f"Redis llen error: {str(e)}")
            return 0

    # ==========================================
    # 集合(Set)操作
    # ==========================================

    def sadd(self, name: str, *values: Any) -> int:
        """
        向集合添加元素
        :param name: 集合名称
        :param values: 要添加的元素
        :return: 添加的元素数量
        """
        try:
            serialized_values = [self._serialize(v) for v in values]
            return self.client.sadd(name, *serialized_values)
        except Exception as e:
            print(f"Redis sadd error: {str(e)}")
            return 0

    def smembers(self, name: str) -> Set[Any]:
        """
        获取集合所有元素
        :param name: 集合名称
        :return: 元素集合
        """
        try:
            values = self.client.smembers(name)
            return {self._deserialize(v) for v in values}
        except Exception as e:
            print(f"Redis smembers error: {str(e)}")
            return set()

    def srem(self, name: str, *values: Any) -> int:
        """
        从集合移除元素
        :param name: 集合名称
        :param values: 要移除的元素
        :return: 移除的元素数量
        """
        try:
            serialized_values = [self._serialize(v) for v in values]
            return self.client.srem(name, *serialized_values)
        except Exception as e:
            print(f"Redis srem error: {str(e)}")
            return 0

    def sismember(self, name: str, value: Any) -> bool:
        """
        判断元素是否在集合中
        :param name: 集合名称
        :param value: 元素
        :return: 是否存在
        """
        try:
            return self.client.sismember(name, self._serialize(value))
        except Exception as e:
            print(f"Redis sismember error: {str(e)}")
            return False

    def scard(self, name: str) -> int:
        """
        获取集合元素数量
        :param name: 集合名称
        :return: 元素数量
        """
        try:
            return self.client.scard(name)
        except Exception as e:
            print(f"Redis scard error: {str(e)}")
            return 0

    # ==========================================
    # 有序集合(Sorted Set)操作
    # ==========================================

    def zadd(self, name: str, mapping: Dict[Any, float]) -> int:
        """
        向有序集合添加元素
        :param name: 有序集合名称
        :param mapping: 元素-分数映射字典
        :return: 添加的元素数量
        """
        try:
            serialized_mapping = {
                self._serialize(k): v
                for k, v in mapping.items()
            }
            return self.client.zadd(name, serialized_mapping)
        except Exception as e:
            print(f"Redis zadd error: {str(e)}")
            return 0

    def zrange(self, name: str, start: int, end: int, withscores: bool = False) -> Union[
        List[Any], List[Tuple[Any, float]]]:
        """
        获取有序集合指定范围的元素（按分数升序）
        :param name: 有序集合名称
        :param start: 起始索引
        :param end: 结束索引，-1表示最后一个元素
        :param withscores: 是否返回分数
        :return: 元素列表或(元素, 分数)列表
        """
        try:
            items = self.client.zrange(name, start, end, withscores=withscores)
            if withscores:
                return [
                    (self._deserialize(item[0]), item[1])
                    for item in items
                ]
            else:
                return [self._deserialize(item) for item in items]
        except Exception as e:
            print(f"Redis zrange error: {str(e)}")
            return []

    def zrevrange(self, name: str, start: int, end: int, withscores: bool = False) -> Union[
        List[Any], List[Tuple[Any, float]]]:
        """
        获取有序集合指定范围的元素（按分数降序）
        :param name: 有序集合名称
        :param start: 起始索引
        :param end: 结束索引，-1表示最后一个元素
        :param withscores: 是否返回分数
        :return: 元素列表或(元素, 分数)列表
        """
        try:
            items = self.client.zrevrange(name, start, end, withscores=withscores)
            if withscores:
                return [
                    (self._deserialize(item[0]), item[1])
                    for item in items
                ]
            else:
                return [self._deserialize(item) for item in items]
        except Exception as e:
            print(f"Redis zrevrange error: {str(e)}")
            return []

    def zrem(self, name: str, *values: Any) -> int:
        """
        从有序集合移除元素
        :param name: 有序集合名称
        :param values: 要移除的元素
        :return: 移除的元素数量
        """
        try:
            serialized_values = [self._serialize(v) for v in values]
            return self.client.zrem(name, *serialized_values)
        except Exception as e:
            print(f"Redis zrem error: {str(e)}")
            return 0

    def zscore(self, name: str, value: Any) -> Optional[float]:
        """
        获取有序集合中元素的分数
        :param name: 有序集合名称
        :param value: 元素
        :return: 分数或None
        """
        try:
            return self.client.zscore(name, self._serialize(value))
        except Exception as e:
            print(f"Redis zscore error: {str(e)}")
            return None

    def zcard(self, name: str) -> int:
        """
        获取有序集合元素数量
        :param name: 有序集合名称
        :return: 元素数量
        """
        try:
            return self.client.zcard(name)
        except Exception as e:
            print(f"Redis zcard error: {str(e)}")
            return 0

    # ==========================================
    # 其他常用操作
    # ==========================================

    def keys(self, pattern: str = '*') -> List[str]:
        """
        查找匹配的键
        :param pattern: 匹配模式，如"user:*"
        :return: 匹配的键列表
        """
        try:
            return [k.decode('utf-8') for k in self.client.keys(pattern)]
        except Exception as e:
            print(f"Redis keys error: {str(e)}")
            return []

    def flushdb(self) -> bool:
        """
        清空当前数据库
        :return: 是否成功
        """
        try:
            return self.client.flushdb()
        except Exception as e:
            print(f"Redis flushdb error: {str(e)}")
            return False


# 实例化默认的Redis客户端
redis_client = RedisClient()
